package com.carey.blog.repository.impl;

import static com.google.appengine.api.datastore.FetchOptions.Builder.withOffset;

import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.carey.blog.framework.latke.Keys;
import com.carey.blog.framework.latke.model.Pagination;
import com.carey.blog.framework.latke.repository.RepositoryException;
import com.carey.blog.framework.latke.repository.gae.AbstractGAERepository;
import com.carey.blog.model.ArchiveDate;
import com.carey.blog.model.Article;
import com.carey.blog.repository.ArchiveDateArticleRepository;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.QueryResultList;

/**
 * Archive date-Article relation Google App Engine repository.
 * 
 */
public final class ArchiveDateArticleGAERepository extends
		AbstractGAERepository implements ArchiveDateArticleRepository {

	/**
	 * Logger.
	 */
	private static final Logger LOGGER = Logger
			.getLogger(ArchiveDateArticleGAERepository.class.getName());

	@Override
	public String getName() {
		return ArchiveDate.ARCHIVE_DATE + "_" + Article.ARTICLE;
	}

	@Override
	public JSONObject getByArchiveDateId(final String archiveDateId,
			final int currentPageNum, final int pageSize)
			throws RepositoryException {
		final Query query = new Query(getName());
		query.addFilter(ArchiveDate.ARCHIVE_DATE + "_" + Keys.OBJECT_ID,
				Query.FilterOperator.EQUAL, archiveDateId);
		query.addSort(Article.ARTICLE + "_" + Keys.OBJECT_ID,
				Query.SortDirection.DESCENDING);

		final PreparedQuery preparedQuery = getDatastoreService()
				.prepare(query);
		final int count = preparedQuery.countEntities(FetchOptions.Builder
				.withDefaults());
		final int pageCount = (int) Math.ceil((double) count
				/ (double) pageSize);

		final JSONObject ret = new JSONObject();
		final JSONObject pagination = new JSONObject();
		try {
			ret.put(Pagination.PAGINATION, pagination);
			pagination.put(Pagination.PAGINATION, pagination);
			pagination.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
			final int offset = pageSize * (currentPageNum - 1);
			final QueryResultList<Entity> queryResultList = preparedQuery
					.asQueryResultList(withOffset(offset).limit(pageSize));
			final JSONArray results = new JSONArray();
			ret.put(Keys.RESULTS, results);
			for (final Entity entity : queryResultList) {
				final Map<String, Object> properties = entity.getProperties();
				final JSONObject e = new JSONObject(properties);

				results.put(e);
			}
		} catch (final JSONException e) {
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
			throw new RepositoryException(e);
		}

		return ret;
	}

	@Override
	public JSONObject getByArticleId(final String articleId)
			throws RepositoryException {
		final Query query = new Query(getName());
		query.addFilter(Article.ARTICLE + "_" + Keys.OBJECT_ID,
				Query.FilterOperator.EQUAL, articleId);
		final PreparedQuery preparedQuery = getDatastoreService()
				.prepare(query);

		final Entity entity = preparedQuery.asSingleEntity();
		if (null == entity) {
			return null;
		}

		final Map<String, Object> properties = entity.getProperties();

		return new JSONObject(properties);
	}

	/**
	 * Gets the {@link ArchiveDateArticleGAERepository} singleton.
	 * 
	 * @return the singleton
	 */
	public static ArchiveDateArticleGAERepository getInstance() {
		return SingletonHolder.SINGLETON;
	}

	/**
	 * Private default constructor.
	 */
	private ArchiveDateArticleGAERepository() {
	}

	/**
	 * Singleton holder.
	 * 
	 */
	private static final class SingletonHolder {

		/**
		 * Singleton.
		 */
		private static final ArchiveDateArticleGAERepository SINGLETON = new ArchiveDateArticleGAERepository();

		/**
		 * Private default constructor.
		 */
		private SingletonHolder() {
		}
	}
}
